﻿using System;
using System.Reflection;

namespace NSDuctTape
{
	internal static class TypeStrings
	{
		public static string ForMethod<T>(T info) where T : MethodBase
		{
			string types = info is MethodInfo ?
				ForType((info as MethodInfo).ReturnType) :
				info is ConstructorInfo ?
				"@" :
				"v";

			// Every method takes a pointer to an instance and a selector.
			types += "@:";

			foreach (ParameterInfo parameter in info.GetParameters())
				types += ForType(parameter.ParameterType);

			return types;
		}

		public static string ForType(Type type)
		{
			// Type encodings have been pulled from http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articles/chapter_5_section_7.html
			string str;
			if (type == typeof(char))
				str = "c";
			else if (type == typeof(int))
				str = "i";
			else if (type == typeof(short))
				str = "s";
			else if (type == typeof(long))
				str = "l";
			// Leaving out typeof(long long) => "q"
			else if (type == typeof(byte))
				str = "C";
			else if (type == typeof(uint))
				str = "I";
			else if (type == typeof(ushort))
				str = "S";
			else if (type == typeof(ulong))
				str = "L";
			// Leaving out typeof(unsigned long long) => "Q"
			else if (type == typeof(float))
				str = "f";
			else if (type == typeof(double))
				str = "d";
			else if (type == typeof(bool))
				str = "B";
			else if (type == typeof(void))
				str = "v";
			else
				str = "@";

			// Things that have been left out:
			// Selector => ":"
			// Array => "[array-type]" where array-type is the number of elements followed by a type
			// Structure => "{structurename=typeencoding}"
			// Union => "(unionname=typeencoding)"
			// bit field => "bNumberOfBits"
			// pointer => "^type"
			// unknown type => "?"

			// Protocol support:
			// const => "r"
			// in => "n"
			// in and out => "N"
			// out => "o"
			// by copy => "O"
			// by ref => "R"
			// one way => "V"

			return str;
		}
	}
}
